﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ISRecord.View.Properties;
using ISRecord.Model;
using System.Collections.ObjectModel;
using ISRecord.View.Services;
using System.Windows.Input;
using Microsoft.Win32;
using Excel = Microsoft.Office.Interop.Excel;
using ISRecord.View.CustomeException;
using System.Runtime.InteropServices;
using ISRecord.Model.CustomeException;

namespace ISRecord.View.ViewsModel
{
    public class BulkOutboxViewModel : WorkspaceViewModel
    {
        ObservableCollection<Outbox> outboxes;
        string excelFilePath;
        string excelSheetName;
        DelegateCommand openExcelFile;
        DelegateCommand trasnportDataCommand;
        DelegateCommand saveCommand;
        Action<string> infoMessage = (msg) => Helper.ShowMessage(msg, MessagePrompetType.ReportInfo);
        Action<string> errorMessage = (msg) => Helper.ShowMessage(msg, MessagePrompetType.ReportError);
        Action<string> confirmationMessage = (msg) => Helper.ShowMessage(msg, MessagePrompetType.AskQuestion);
        bool canSaveData;
        public BulkOutboxViewModel()
        {
            base.DisplayName = Resources.BulkOutboxesDisplayName;

        }

        #region "Commands"
        public ICommand OpenExcelFileCommand
        {
            get
            {
                if (openExcelFile == null)
                {
                    openExcelFile = new DelegateCommand(OpenFile);
                }
                return openExcelFile;
            }
        }
        private void OpenFile(object obj)
        {
            OpenFileDialog dg = new OpenFileDialog();
            dg.Filter = "Excel Files (*.xls, *.xlsx)|*.xls;*.xlsx";
            if (dg.ShowDialog() == true)
            {
                this.ExcelFilePath = dg.FileName;
                try
                {
                    this.ExcelSheetName = PrompetUserToSelectSheet(ExcelFilePath);
                    if (this.ExcelSheetName == null)
                    {
                        ExcelFilePath = null;
                        infoMessage(Resources.NoSheetSelectedMsg);
                        Logger.Warning("User didn't select an Excel Sheet", "BulkOutboxViewModel", "OpenFile");
                    }
                }
                catch (ReadingFromExcelException ex)
                {
                    Logger.Error(ex, "BulkOutboxViewModel", "OpenFile");
                    string msg = ex.Message;
                    errorMessage(msg);
                    ExcelFilePath = null;
                }
            }
        }
        public ICommand TransportDataCommand
        {
            get
            {
                if (trasnportDataCommand == null)
                {
                    trasnportDataCommand = new DelegateCommand(LoadData, CanLoadData, "Load Data");
                }
                return trasnportDataCommand;
            }
        }
        private void LoadData(object obj)
        {
            //Call this in case of error.
            Action<string, Exception> OnError = (string msg, Exception ex) =>
            {
                Logger.Error(ex, "BulkOutboxViewModel", "LoadData");
                Helper.ShowMessage(msg, MessagePrompetType.ReportError);
            };
            ExcelData excel = new ExcelData();
            try
            {
                var data = excel.ReadFrom(ExcelFilePath, ExcelSheetName);
                Outboxes = new ObservableCollection<Outbox>(data);
                CanSaveData = true;
            }
            catch (ArgumentNullException ex)
            {
                string msg = Resources.ArgumentNullExceptionMsg;
                OnError(msg, ex);
            }
            catch (ReadingFromExcelException ex)
            {
                string msg = string.Format("{0}{1}{2}", ex.Message, "\n", ex.InnerException.Message);
                OnError(msg ,ex);
            }
            catch (InvalidOperationException ex)
            {
                string msg = ex.Message;
                OnError(msg, ex);
            }
            catch (FormatException ex)
            {
                string msg = ex.Message;
                OnError(msg ,ex);
            }

        }
        private bool CanLoadData(object obj)
        {
            return !(string.IsNullOrEmpty(ExcelFilePath) || string.IsNullOrEmpty(ExcelSheetName));
        }

        public ICommand SaveCommand
        {
            get
            {
                if (saveCommand == null)
                {
                    saveCommand = new DelegateCommand(Save, CanSave, "Save");
                }
                return saveCommand;
            }

        }
        public bool CanSave(object obj)
        {
            return !(Outboxes == null || Outboxes.Count <= 0);
        }

        #endregion

        #region "Properties"
        public string CurrentWizardPage
        {
            get;
            set;
        }

        public bool CanSaveData
        {
            get
            {
                if (Outboxes == null) return false;
                return Outboxes.Count != 0;
            }
            set
            {
                canSaveData = value;
                RaisePropertyChanged("CanSaveData");
            }
        }
        public string PrefixBeforSubject
        {
            get { return Settings.Default.PrefixBeforSubject; }
            set
            {
                if (Settings.Default.PrefixBeforSubject != value)
                {
                    Settings.Default.PrefixBeforSubject = value;
                    RaisePropertyChanged("PrefixBeforSubject");
                }
            }

        }
        public string PrefixAfterSubject
        {
            get { return Settings.Default.PrefixAfterSubject; }
            set
            {
                if (Settings.Default.PrefixAfterSubject != value)
                {
                    Settings.Default.PrefixAfterSubject = value;
                    RaisePropertyChanged("PrefixAfterSubject");
                }
            }
        }
        public ObservableCollection<Outbox> Outboxes
        {
            get
            {
                return outboxes;
            }
            private set
            {
                outboxes = value;
                RaisePropertyChanged("Outboxes");
            }
        }

        public string ExcelFilePath
        {
            get { return excelFilePath; }
            private set
            {
                if (value != excelFilePath)
                {
                    excelFilePath = value;
                    RaisePropertyChanged("ExcelFilePath");
                }
            }
        }
        public string ExcelSheetName
        {
            get { return excelSheetName; }
            private set
            {
                if (value != excelSheetName)
                {
                    excelSheetName = value;
                    RaisePropertyChanged("ExcelSheetName");
                }
            }
        }

        #endregion

        #region "Base implementation"
        

        protected void Save(object obj)
        {
            Sender2006Entities context = new Sender2006Entities();
            using (OutboxRepository repository = new OutboxRepository(context))
            {
                foreach (Outbox entity in Outboxes)
                {
                    repository.Add(entity);
                }
                //ToDo: Catch any exception from save.
                try
                {
                    repository.Save();
                    ModelController(ModelState.Saved);
                }
                catch (DataModelException ex)
                {
                    Reset();
                    Logger.Error(ex, "BulkOutboxViewModel", "Save");
                    errorMessage(ex.Message);
                }
               
            }

        }
        #endregion

        #region "Helper Functions"
        private enum ModelState
        { 
            Saved,
            Loaded
        }
        private void ModelController(ModelState state)
        {
            switch (state)
            {
                case ModelState.Saved:
                    Reset();
                    break;
                case ModelState.Loaded:
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>
        /// <returns>Selected sheet name. Null if no selection made.</returns>
        /// <exception cref="ReadingFromExcelException"
        private string PrompetUserToSelectSheet(string path)
        {
            List<string> sheetNames = new List<string>();
            Excel.Application excelApp = null;
            try
            {
                excelApp = new Excel.Application();
                Excel.Workbook workBook = excelApp.Workbooks.Open(path);
                int numSheets = workBook.Sheets.Count;
                for (int sheetNum = 1; sheetNum < numSheets + 1; sheetNum++)
                {
                    Excel.Worksheet sheet = (Excel.Worksheet)workBook.Sheets[sheetNum];
                    sheetNames.Add(sheet.Name);
                }
                SelectSheetDialog sheetDg = new SelectSheetDialog(sheetNames);
                if (sheetDg.ShowDialog() == true)
                {
                    return sheetDg.SelectedSheetName;
                }
                //ToDo: Think again for how react if no sheet selected.
                //The decision made for now is to return null. That said the caller must check to null befor proceed.
                return null;
            }
            catch (Exception ex)
            {

                throw new ReadingFromExcelException(Resources.ReadingFromExcelExceMsg, ex);

            }
            finally
            {
                if (excelApp != null)
                {
                    excelApp.DisplayAlerts = false;
                    excelApp.Quit();
                    Marshal.ReleaseComObject(excelApp);
                }
            }
            


        }
        #endregion

        public void Reset()
        {
            ExcelSheetName = string.Empty;
            PrefixBeforSubject = string.Empty;
            PrefixAfterSubject = string.Empty;
            ExcelFilePath = string.Empty;
            CanSaveData = false;
            Outboxes.Clear();
        }
    }
}
